/*
	Arithmetic Logic Unit
*/
module alu 
(

	input 	wire	[31:0] 	    operand1,
	input 	wire	[31:0] 	    operand2,
    input   wire    [31:0]      pc,


	input	wire	[04:0]		shamt,
	input 	wire	[02:0] 		func,     			// Operation
	input	wire    			aluFuncSel, 		// Operation select (+/-, Logical/Arithmetic)
    input   wire                aluriOp,

	output	wire	[31:0] 		aluRes,     		// ALU result. 
	output	wire	[31:0]		specialAdderRes,	// Calculate address
	output	wire	[31:0]		pcPlus4Res			// PC + 4
);
								
	wire			[31:0]		addOrSubRes;
	wire			[31:0]		sltRes;
	wire			[31:0]		sltuRes;
	wire			[31:0]		xorRes;
	wire			[31:0]		orRes;
	wire			[31:0]		andRes;
	wire			[31:0]		shiftRes;
	
	barrelShifter 				barrelShifter
	(
			.dataIn				(operand1),
			.op					({func[2],aluFuncSel}),
			.shamt				((aluriOp ? shamt : operand2[4:0])),
			.dataOut			(shiftRes)
	);
	
	assign	specialAdderRes = operand1 + operand2;
	assign	pcPlus4Res		= pc + 32'h0000_0004;
	
	// ALUri & ALUrr
	assign	addOrSubRes = aluriOp ? operand1 + operand2 : ( aluFuncSel ? operand1 - operand2 : operand1 + operand2 );   // ADD/SUB
	assign 	sltRes 		= ($signed(operand1) < $signed(operand2)) ? 32'b1 : 32'b0 ;       								// SLT
	assign 	sltuRes 	= operand1 < operand2 ? 32'b1 : 32'b0;                          								// SLTU
	assign 	xorRes 		= operand1 ^ operand2;                                            								// XOR
	assign 	orRes 		= operand1 | operand2;                                            								// OR
	assign 	andRes 		= operand1 & operand2;                                            								// AND
	/*
    The shift operation is completed by the barrel shifter.
	assign 	sllRes 		=  shiftRes                                      												// SLL
	assign 	srlOrSraRes =  shiftRes																	    				// SRL/SRA
	*/
    assign aluRes       =   ( func == 3'b000 ? addOrSubRes  :32'b0 ) |
                            ( func == 3'b010 ? sltRes       :32'b0 ) |
                            ( func == 3'b011 ? sltuRes      :32'b0 ) |
                            ( func == 3'b100 ? xorRes       :32'b0 ) |
                            ( func == 3'b110 ? orRes        :32'b0 ) |
                            ( func == 3'b111 ? andRes       :32'b0 ) |
                            ( func == 3'b001 ? shiftRes     :32'b0 ) |
                            ( func == 3'b101 ? shiftRes     :32'b0 ) ; 
endmodule